package com.xiaoxin.experience.util;

import com.xiaoxin.experience.service.net.NetMonitor;
import lombok.extern.slf4j.Slf4j;

import javax.net.ssl.HttpsURLConnection;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Objects;

/**
 * <p>Simple life, simple work, don't complicate</p>
 *
 * @author 小心
 * @version 1.0.0
 * @date 2021/7/17
 */
@Slf4j
public class DownloadUtil
{

    private static final int CONNECT_TIMEOUT_MILLIS = 10 * 1000;

    private static final int READ_TIMEOUT_MILLIS = 10 * 1000;

    private DownloadUtil() {}

    static
    {
        //设置https协议访问
        System.setProperty("https.protocols", "TLSv1.2,SSLv3");
        ignoreSSL();
    }

    public static byte[] downloadTransToBytes(String sourceFileUrl)
    {
        try
        {
            URL url = new URL(sourceFileUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //设置超时间为3秒
            conn.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);
            //防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            //设置读取的超时时间,避免长时间读取
            conn.setReadTimeout(READ_TIMEOUT_MILLIS);
            //得到输入流
            try(InputStream inputStream = conn.getInputStream())
            {
                //获取字节数组
                byte[] bytes = IOUtil.readInputStream(inputStream);
                if (Objects.nonNull(bytes))
                {
                    NetMonitor.stats(bytes.length);
                }
                return bytes;
            }
        }
        catch (Exception e)
        {
            return null;
        }
    }

    private static void ignoreSSL()
    {
        HttpsURLConnection.setDefaultSSLSocketFactory(IgnoredSSLSocketFactory.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier((hostname,session) -> true);
    }

    public static String downloadFileName(String url)
    {
        int fileNameStartIndex = url.lastIndexOf("/");
        return url.substring(fileNameStartIndex + 1);
    }

    public static byte[] downloadUntilSuccess(String sourceFileUrl)
    {
        byte[] bytes = downloadTransToBytes(sourceFileUrl);
        while (Objects.isNull(bytes))
        {
            bytes = downloadTransToBytes(sourceFileUrl);
        }
        return bytes;
    }

    public static byte[] downloadLimitRetry(String sourceFileUrl, int retry)
    {
        byte[] bytes = downloadTransToBytes(sourceFileUrl);
        while (retry  > 0)
        {
            retry--;
            if (bytes == null)
            {
                bytes = downloadTransToBytes(sourceFileUrl);
            }
        }
        return bytes;
    }

    public static boolean downloadToFile(String sourceFileUrl, String savePath)
    {
        try
        {
            //设置连接超时的时间
            URL url = new URL(sourceFileUrl);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);
            httpURLConnection.setReadTimeout(READ_TIMEOUT_MILLIS);
            try(InputStream inputStream = httpURLConnection.getInputStream();
                FileOutputStream fileOutputStream = new FileOutputStream(savePath))
            {
                ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
                fileOutputStream.getChannel().transferFrom(readableByteChannel,0,Long.MAX_VALUE);
            }
            return true;
        }
        catch (Exception e)
        {
            log.error("download fail :", e);
        }
        return false;
    }

    public void resumeDownload(String sourceFileUrl, String fullFilePath)
    {
        try
        {
            URL url = new URL(sourceFileUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("HEAD");
            long contentLength = conn.getContentLengthLong();
            File file = new File(fullFilePath);
            long existLength = file.length();
            if (existLength < contentLength)
            {
                conn.setRequestProperty("Range", "bytes=" + existLength + "-" + contentLength);
            }
            try (ReadableByteChannel readableByteChannel = Channels.newChannel(conn.getInputStream());
                 FileOutputStream fileOutputStream = new FileOutputStream(file, true))
            {
                fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
            }
        }
        catch (Exception e)
        {
            log.error("resume download fail: ",e);
        }
    }

    public static long getContentLength(String sourceFileUrl)
    {
        HttpURLConnection conn = null;
        try
        {
            URL url = new URL(sourceFileUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("HEAD");
            return conn.getContentLengthLong();
        }
        catch (Exception e)
        {
            log.error("get content length fail: ",e);
        }
        return 0;
    }

    public static String consumeTime(long startTimeMills)
    {
        long consumeSecond = (System.currentTimeMillis() - startTimeMills) / 1000;
        if (consumeSecond < 60)
        {
            return consumeSecond + "秒";
        }
        long consumeMinute = consumeSecond/60;
        if (consumeMinute < 60)
        {
            return consumeMinute + "分" + consumeSecond%60 + "秒";
        }
        long consumeHour = consumeMinute/60;
        return consumeHour + "时" + consumeMinute%60 + "分" + consumeSecond%60 + "秒";
    }

    public static void consumeLog(long startTimeMills)
    {
        log.info("总共下载文件耗时： {}",consumeTime(startTimeMills));
    }

    public static String urlDecode(String sourceFileUrl, String enc)
    {
        if (!StringUtil.validate(sourceFileUrl))
        {
            return "";
        }
        enc = StringUtil.validate(enc) ? enc : "UTF-8";
        try
        {
            return URLDecoder.decode(sourceFileUrl, enc);
        }
        catch (UnsupportedEncodingException e)
        {
            log.error("decode url fail: ",e);
        }
        return "";
    }
}
